package com.ndp.fb.walle.util;


import com.ndp.fb.constant.CommonConstants;
import com.ndp.fb.util.DateFormatUtil;
import com.ndp.fb.walle.annotation.BoPoFiledName;
import com.ndp.fb.walle.annotation.DateTimeFormat;
import com.ndp.fb.walle.annotation.Exclusion;
import com.ndp.fb.walle.annotation.MultiLevelField;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Locale;

/**
 * Created by Administrator on 14-7-14.
 */
public class ConversionUtils {
    /**
     * LOG日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ConversionUtils.class);

    /**
     * @param from from
     * @param to   to
     * @description bo转vo
     * @author Sisi 创建时间 2014年7月15日 下午3:12:25
     */
    public static void conversion(Object from, Object to) {

        if (null == from || null == to) {
            return;
        }

        String inputFieldName = null;
        String datePattern = null;
        boolean isDateStr = false;
        String[] multiLevelFields = null;
        boolean ismultiLevelField = false;
        boolean isExclusion = false;

        // 以Vo需要的字段为依据，将Bo中的字段值赋给Vo
        Class<?> outputClass = to.getClass();
        Field[] fromFields = new Field[0];
        Field[] outputFields = getFields(fromFields, outputClass);
        for (Field outputField : outputFields) {
            isDateStr = false;
            ismultiLevelField = false;
            isExclusion = false;

            // 1.获取字段注解
            Annotation[] anns = outputField.getDeclaredAnnotations();

            // 2.根据注解进行不同操作
            inputFieldName = outputField.getName();
            if (null != anns && 0 < anns.length) {
                for (Annotation annotation : anns) {
                    if (annotation instanceof BoPoFiledName) {
                        inputFieldName = ((BoPoFiledName) annotation).value();
                    } else if (annotation instanceof DateTimeFormat) {
                        datePattern = ((DateTimeFormat) annotation).pattern();
                        isDateStr = true;
                    } else if (annotation instanceof MultiLevelField) {
                        ismultiLevelField = true;
                        multiLevelFields = ((MultiLevelField) annotation).value().split(CommonConstants.SYMBOL_POINT);
                    } else if (annotation instanceof Exclusion) {
                        isExclusion = true;
                    } else {
                        logger.info("ConversionUtils->conversion:has other annotation.");
                    }
                }
            }

            // 不处理该字段
            if (isExclusion) {
                continue;
            }

            // 3.获取Bo对应的字段值
            Object result = accessBoFieldValue(from, inputFieldName, ismultiLevelField, multiLevelFields);

            // 4.转成指定格式的时间字符串
            if (isDateStr) {
                result = getDateStrByPattern(datePattern, result);
            }

            // 5.给Vo赋值
            fillVoFiledValue(to, outputClass, outputField, result);

        }
    }

    private static Field[] getFields(Field[] oldFields, Class<?> outputClass) {
        Field[] fields = outputClass.getDeclaredFields();
        Field[] newFields = concat(oldFields, fields);
        Class superclass = outputClass.getSuperclass();
        if (null != superclass) {
            return getFields(newFields, superclass);
        } else {
            return newFields;
        }
    }

    private static Field[] concat(Field[] a, Field[] b) {
        Field[] c = new Field[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);

        return c;
    }



    /**
     * @param datePattern 时间模板
     * @param date        时间
     * @return 时间字符串
     * @description 根据指定模板获取时间字符串
     * @author Sisi
     * 创建时间 2014年7月18日 下午2:12:19
     */
    private static String getDateStrByPattern(String datePattern, Object date) {
        String dateStr = "";

        if (date instanceof String) {
            dateStr = date.toString();

        } else if (date instanceof Long) {
//            dateStr = DateFormatUtil.format((Long) date, datePattern);
            dateStr = DateFormatUtils.format((Long) date, datePattern);

        } else if (date instanceof Date) {
            dateStr = DateFormatUtil.format((Date) date, datePattern);
        }

        return dateStr;
    }

    /**
     * @param vo          vo
     * @param outputClass outputClass
     * @param outputField outputField
     * @param result      result
     * @description 根据反射回填Vo对应的字段值
     * @author Sisi 创建时间 2014年7月15日 下午4:21:53
     */
    private static void fillVoFiledValue(Object vo, Class<?> outputClass, Field outputField, Object result) {
        StringBuilder outputMethodName = new StringBuilder();
        String firstChar = outputField.getName().substring(0, 1).toUpperCase(Locale.getDefault());
        String otherChar = outputField.getName().substring(1);
        outputMethodName.append(CommonConstants.METHOD_PREFIX_SET);
        outputMethodName.append(firstChar);
        outputMethodName.append(otherChar);
        Method outputMethod;
        try {
            outputMethod = outputClass.getMethod(outputMethodName.toString(), outputField.getType());
            outputMethod.invoke(vo, result);
        } catch (NoSuchMethodException e) {
            logger.error(e.getMessage());
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage());
        } catch (InvocationTargetException e) {
            logger.error(e.getMessage());
        }

    }

    /**
     * @param bo                bo
     * @param fieldName         字段名
     * @param ismultiLevelField 标识是否是多级字段
     * @param multiLevelFields  多级字段名
     * @return Object
     * @description 获取Bo的字段值
     * @author Sisi 创建时间 2014年7月15日 下午4:14:23
     */
    private static Object accessBoFieldValue(Object bo, String fieldName, boolean ismultiLevelField,
                                             String[] multiLevelFields) {
        Object result = null;
        try {
            if (ismultiLevelField && null != multiLevelFields && 0 < multiLevelFields.length) {
                Object obj = bo;
                for (String filed : multiLevelFields) {
                    obj = accessValueByFiled(obj, filed);
                }

                result = obj;
            } else {
                result = accessValueByFiled(bo, fieldName);
            }
        } catch (NoSuchFieldException e) {
            logger.error(e.getMessage());
        } catch (NoSuchMethodException e) {
            logger.error(e.getMessage());
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage());
        } catch (InvocationTargetException e) {
            logger.error(e.getMessage());
        }

        return result;
    }

    /**
     * @param bo        bo
     * @param fieldName fieldName
     * @return 方法值
     * @throws NoSuchFieldException                        NoSuchFieldException
     * @throws NoSuchMethodException                       NoSuchMethodException
     * @throws IllegalAccessException                      IllegalAccessException
     * @throws java.lang.reflect.InvocationTargetException InvocationTargetException
     * @description 通过字段名获取字段值
     * @author Sisi 创建时间 2014年7月15日 下午2:49:58
     */
    private static Object accessValueByFiled(Object bo, String fieldName) throws NoSuchFieldException,
            NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Class<?> objeClass = bo.getClass();

        //Field fileld = objeClass.getDeclaredField(fieldName);
        Field fileld = getField(objeClass, fieldName);
        StringBuilder methodName = new StringBuilder();

        String firstChar = fieldName.substring(0, 1).toUpperCase(Locale.getDefault());
        String otherChar = fieldName.substring(1);
        if (fileld.getType().isAssignableFrom(boolean.class)) {
            methodName.append(CommonConstants.METHOD_PREFIX_IS);
        } else {
            methodName.append(CommonConstants.METHOD_PREFIX_GET);
        }
        methodName.append(firstChar);
        methodName.append(otherChar);

        Method inputMethod = objeClass.getMethod(methodName.toString());
        return inputMethod.invoke(bo);
    }

    private static Field getField(Class<?> objeClass, String fieldName) {
        Field[] fields = getFields(new Field[0], objeClass);
        for (Field field : fields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }

        return null;
    }

    public  static   String replaceConnectionObjectName(String originConnectionObjectName, String regex, String replacement){
        if (StringUtils.isEmpty(originConnectionObjectName)){
            return null;
        }

        String replaced = originConnectionObjectName.replaceAll(regex, replacement);
        String[] elements = replaced.split(replacement);
        StringBuilder sb = new StringBuilder();
        boolean isFirst = true;
        for (String element : elements) {
            if (StringUtils.isEmpty(element)) {
                continue;
            }

            if (!isFirst) {
                sb.append(replacement);
            }

            sb.append(element);
            isFirst = false;
        }
        return sb.toString();
    }

}
